/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package wave;

import ast.*;
import java.io.StringReader;
import base.*;
import base.TrackNode.Echo;
import base.TrackNode.Rule;
import java.io.IOException;
import trackmsg.ActivateMsg;
import trackmsg.CreateMsg;
import trackmsg.EchoMsg;
import trackmsg.ExpandsMsg;
import trackmsg.TrackCtrlMsg;
/**
 *
 * @author Tue
 */
public class WaveHeadParser extends Thread{
    private SynchronousQueue<Wave> waveQueue;
    private KN kn;
    private WaveInterpreter wi;
    private Wave w;
    public Thread myThread;
    public WaveHeadParser(WaveInterpreter wi, Wave w){
        this.waveQueue = wi.getWaveQueue();
        this.kn = wi.getKN();
        this.wi = wi;
        this.w = w;
        myThread = this;
    }
    public void run() {
        try {
            parserWave();
        } catch (ParseException parserException){
            System.err.println("Loi phan tich cu phap (Parser): " + parserException.getMessage());
        } catch (TokenMgrError tokenManagerError){
            System.err.println("Loi phan tich tu to (Token): " + tokenManagerError.getMessage());
        }
    }
    public void parserWave() throws ParseException, TokenMgrError {
        
        WAVEParser parser = new WAVEParser(new StringReader(w.getWaveString()));
        try {
            SimpleNode head = parser.WaveHead();
            String tail = parser.WaveTail();
            head.setStringAll();

            boolean isTrackMode = w.getWaveEnv().getTrackAddress() != null;
            ASTZone zone = (ASTZone)head.jjtGetChild(0);
            //Neu so sector ma > 1 thi chia thanh nhieu sector
            //va noi vao tail dua vao hang doi
            if (zone.jjtGetNumChildren() > 1) {
                if(isTrackMode){ //Neu trong che do track thi expands va gui vao track queue
                    for (int i = 0; i < zone.jjtGetNumChildren(); i++) {
                        String waveString = ((SimpleNode)zone.jjtGetChild(i)).getString();
                        if(!tail.equals("")) waveString += "." + tail;
                        TrackNode currentTrack = wi.getTrackForest().
                                getTrackNode(w.getWaveEnv().getTrackAddress());
                        TrackCtrlMsg msg = new ExpandsMsg(currentTrack, waveString,
                                w.getWaveEnv().clone());
                        wi.getTrackQueue().incoming(msg);//Gui vao cuoi track queue
                    }
                    //Activate all expanded track
                    TrackNode currentTrack = wi.getTrackForest().
                                getTrackNode(w.getWaveEnv().getTrackAddress());
                    TrackCtrlMsg msg = new ActivateMsg(currentTrack);
                    wi.getTrackQueue().incoming(msg);
                } else {
                    for (int i = zone.jjtGetNumChildren() - 1; i >= 0; i--) {
                        String waveString = ((SimpleNode)zone.jjtGetChild(i)).getString();
                        if(!tail.equals("")) waveString += "." + tail;
                        Wave newWave = new Wave(waveString, w.getWaveEnv().clone());
                        waveQueue.incomingFront(newWave);//Dua vao dau wave queue
                    }
                }
            } else if (zone.jjtGetNumChildren() == 1) { //Neu so sector = 1
                SimpleNode node = (SimpleNode)zone.jjtGetChild(0);

                if( node instanceof ASTSector){//Neu node hien tai la ASTSector                    
                    if( node.jjtGetNumChildren() == 1){
                        SimpleNode simpleMove = (SimpleNode) node.jjtGetChild(0);
                        if ( simpleMove instanceof ASTHop){
                            ASTHopExecution waveExec = new ASTHopExecution(this, w.getWaveEnv());
                            waveExec.execute((ASTHop)(simpleMove), tail);
                        } else if( simpleMove instanceof ASTHopAhead){
                            ASTHopAheadExecution waveExec = new ASTHopAheadExecution(this, w.getWaveEnv());
                            waveExec.execute((ASTHopAhead)(simpleMove), tail);
                        } else if( simpleMove instanceof ASTHopPlusAhead){
                            ASTHopPlusAheadExecution waveExec = new ASTHopPlusAheadExecution(this, w.getWaveEnv());
                            waveExec.execute((ASTHopPlusAhead)(simpleMove), tail);
                        } else if(simpleMove instanceof ASTSysCall) {
                            ASTSysCallExecution sysExec= new ASTSysCallExecution(this, w.getWaveEnv());
                            sysExec.execute((ASTSysCall)(simpleMove), tail);
                        } else if (simpleMove instanceof ASTAssignSubscript) {
                            ASTAssignRightSubExecution asExec = new ASTAssignRightSubExecution(this, w.getWaveEnv());
                            asExec.execute((ASTAssignSubscript)simpleMove, tail);
                        } else if (simpleMove instanceof ASTAssignIndexOf) {
                            ASTAssignRightIndexExecution asExec = new ASTAssignRightIndexExecution(this, w.getWaveEnv());
                            asExec.execute((ASTAssignIndexOf)simpleMove, tail);
                        } else if (simpleMove instanceof ASTAssign) {
                            ASTAssignExecution asExec = new ASTAssignExecution(this, w.getWaveEnv());
                            asExec.execute((ASTAssign)simpleMove, tail);
                        } else if (simpleMove instanceof ASTSplit) {
                            ASTSplitExecution asSplit = new ASTSplitExecution(this, w.getWaveEnv());
                            asSplit.execute((ASTSplit) simpleMove, tail);
                        } else if (simpleMove instanceof ASTSum) {
                            ASTSumExecution sumExec = new ASTSumExecution(this, w.getWaveEnv());
                            sumExec.execute((ASTSum)simpleMove, tail);
                        } else if (simpleMove instanceof ASTJoin) {
                            ASTJoinExecution asJoin = new ASTJoinExecution(this, w.getWaveEnv());
                            asJoin.execute((ASTJoin) simpleMove, tail);
                        } else if (simpleMove instanceof ASTFunctionCall) {
                            ASTFunctionCallExecution funcCall = new ASTFunctionCallExecution(this, w.getWaveEnv());
                            funcCall.execute((ASTFunctionCall)simpleMove, tail);
                        } else if (simpleMove instanceof ASTDifference) {
                            ASTDifferenceExecution diffExec = new ASTDifferenceExecution(this, w.getWaveEnv());
                            diffExec.execute((ASTDifference)simpleMove, tail);
                        } else if (simpleMove instanceof ASTGreaterThan){
                            ASTGreaterThanExecution gtExec = new ASTGreaterThanExecution(this, w.getWaveEnv());
                            gtExec.execute((ASTGreaterThan)simpleMove, tail);
                        } else if (simpleMove instanceof ASTEquals){
                            ASTEqualsExecution eqExec = new ASTEqualsExecution(this, w.getWaveEnv());
                            eqExec.execute((ASTEquals)simpleMove, tail);
                        } else if (simpleMove instanceof ASTNotEquals){
                            ASTNotEqualExecution notEqExec = new ASTNotEqualExecution(this, w.getWaveEnv());
                            notEqExec.execute((ASTNotEquals)simpleMove, tail);
                        } else if (simpleMove instanceof ASTLessThan){
                            ASTLessThanExecution lessExec = new ASTLessThanExecution(this, w.getWaveEnv());
                            lessExec.execute((ASTLessThan)simpleMove, tail);
                        } else if (simpleMove instanceof ASTLessEqual){
                            ASTLessEqualExecution lessEqExec = new ASTLessEqualExecution(this, w.getWaveEnv());
                            lessEqExec.execute((ASTLessEqual)simpleMove, tail);
                        } else if (simpleMove instanceof ASTGreaterEqual){
                            ASTGreaterEqualExecution grEqExec = new ASTGreaterEqualExecution(this, w.getWaveEnv());
                            grEqExec.execute((ASTGreaterEqual)simpleMove, tail);
                        } else if (simpleMove instanceof ASTContains){
                            ASTContainsExecution containExec = new ASTContainsExecution(this, w.getWaveEnv());
                            containExec.execute((ASTContains)simpleMove, tail);
                        } else if (simpleMove instanceof ASTNotContains){
                            ASTNotContainsExecution notContainExec = new ASTNotContainsExecution(this, w.getWaveEnv());
                            notContainExec.execute((ASTNotContains)simpleMove, tail);
                        } else if (simpleMove instanceof ASTConcat) {
                            ASTConcatExecution concatExec = new ASTConcatExecution(this, w.getWaveEnv());
                            concatExec.execute((ASTConcat) simpleMove, tail);
                        } else if (simpleMove instanceof ASTStopTrue){
                            ASTStopTrueExecution stopTrueExec = new ASTStopTrueExecution(this, w.getWaveEnv());
                            stopTrueExec.execute();
                        } else if (simpleMove instanceof ASTStopDone){
                            ASTStopDoneExecution stopDoneExec = new ASTStopDoneExecution(this, w.getWaveEnv());
                            stopDoneExec.execute();
                        } else if (simpleMove instanceof ASTStopFalse){
                            ASTStopFalseExecution stopFalseExec = new ASTStopFalseExecution(this, w.getWaveEnv());
                            stopFalseExec.execute();
                        } else if (simpleMove instanceof ASTStopAbort){
                            ASTStopAbortExecution stopAbortExec = new ASTStopAbortExecution(this, w.getWaveEnv());
                            stopAbortExec.execute();
                        } else if (simpleMove instanceof ASTQuotient) {
                            ASTQuotientExecution quote = new ASTQuotientExecution(this, w.getWaveEnv());
                            quote.execute((ASTQuotient)simpleMove, tail);
                        } else if (simpleMove instanceof ASTProduct) {
                            ASTProductExecution prod = new ASTProductExecution(this, w.getWaveEnv());
                            prod.execute((ASTProduct)simpleMove, tail);
                        } else if(simpleMove instanceof ASTTerminalOutput){
                            ASTTerminalOutputExecution ter = new ASTTerminalOutputExecution(this, w.getWaveEnv());
                            ter.execute((ASTTerminalOutput)simpleMove, tail);
                        } else if (simpleMove instanceof ASTRelease) {                            
                            ASTReleaseExecution rle = new ASTReleaseExecution(this, w.getWaveEnv());
                            rle.execute((ASTRelease) simpleMove, tail);                            
                        } else if(simpleMove instanceof ASTStay){
                            if(isTrackMode){
                                TrackNode fromTrack = wi.getTrackForest().getTrackNode(w.getWaveEnv().getTrackAddress());
                                EchoMsg msg = new EchoMsg(fromTrack, Echo.TRUE);
                                wi.getTrackQueue().incoming(msg);
                            }
                        } else if(simpleMove instanceof ASTHopMinusAhead){
                            ASTHopMinusAheadExecution hop = new ASTHopMinusAheadExecution(this,w.getWaveEnv());
                            hop.execute((ASTHopMinusAhead)simpleMove, tail);
                        } else if(simpleMove instanceof ASTOrSequential){
                            //Tao mot track moi bang viec gui mot msg CREATE vao TQ
                            //msg bao gom cac thong tin nhu sau:
                            //+ Loai msg: CREATE
                            //+ Luat se gan vao track node vua duoc tao ra
                            //+ Track hien tai: null
                            //+ Chuoi Wave trong Rule
                            //+ Suspended wave tail
                            //+ Wave Environment
                            ASTOrSequential ruleNode = (ASTOrSequential) simpleMove;
                            TrackCtrlMsg msg = new CreateMsg(TrackNode.Rule.OS,
                                    ruleNode.getWave(), tail, w.getWaveEnv());
                            wi.getTrackQueue().incoming(msg);
                        } else if(simpleMove instanceof ASTCreate){
                            ASTCreate ruleNode = (ASTCreate) simpleMove;
                            TrackCtrlMsg msg = new CreateMsg(TrackNode.Rule.CR,
                                    ruleNode.getWave(), tail, w.getWaveEnv());
                            wi.getTrackQueue().incoming(msg);
                        } else if(simpleMove instanceof ASTOrParallel){
                            ASTOrParallel ruleNode = (ASTOrParallel) simpleMove;
                            TrackCtrlMsg msg = new CreateMsg(TrackNode.Rule.OP,
                                    ruleNode.getWave(), tail, w.getWaveEnv());
                            wi.getTrackQueue().incoming(msg);
                        } else if(simpleMove instanceof ASTAndSequential){
                            ASTAndSequential ruleNode = (ASTAndSequential) simpleMove;
                            TrackCtrlMsg msg = new CreateMsg(TrackNode.Rule.AS,
                                    ruleNode.getWave(), tail, w.getWaveEnv());
                            wi.getTrackQueue().incoming(msg);
                        } else if(simpleMove instanceof ASTAndParallel){
                            ASTAndParallel ruleNode = (ASTAndParallel) simpleMove;
                            TrackCtrlMsg msg = new CreateMsg(TrackNode.Rule.AP,
                                    ruleNode.getWave(), tail, w.getWaveEnv());
                            wi.getTrackQueue().incoming(msg);
                        } else if(simpleMove instanceof ASTSeq){
                            ASTSeq ruleNode = (ASTSeq) simpleMove;
                            TrackCtrlMsg msg = new CreateMsg(TrackNode.Rule.SQ,
                                    ruleNode.getWave(), tail, w.getWaveEnv());
                            wi.getTrackQueue().incoming(msg);
                        } else if(simpleMove instanceof ASTRepeat){
                            ASTRepeat rp = (ASTRepeat) simpleMove;
                            TrackCtrlMsg msg = new CreateMsg(Rule.RP, rp.getWave(), tail, w.getWaveEnv());
                            wi.getTrackQueue().incoming(msg);
                        } else if(simpleMove instanceof ASTRandom){
                            ASTRandom rp = (ASTRandom) simpleMove;
                            TrackCtrlMsg msg = new CreateMsg(Rule.RD, rp.getWave(), tail, w.getWaveEnv());
                            wi.getTrackQueue().incoming(msg);
                        } else if(simpleMove instanceof ASTEmptyMove){
                            Utilities.WPPrint("EMTY MOVE! " + w.getWaveEnv());
                            if(isTrackMode && tail.equals("")){
                                TrackCtrlMsg msg = new EchoMsg(wi.getTrackForest().
                                        getTrackNode(w.getWaveEnv().getTrackAddress()), Echo.TRUE, w.getWaveEnv());
                                wi.getTrackQueue().incoming(msg);
                            } else if(!tail.equals("")){
                                Wave newWave = new Wave(tail, new WaveEnvironment(w.getWaveEnv()));
                                wi.getWaveQueue().incoming(newWave);
                            }
                        }
                    }
                } else if ( node instanceof ASTZoneList){//Neu node hien tai la ASTZoneList
                    String wave = "";
                    for(int i=0; i<node.jjtGetNumChildren(); i++){
                        wave += ((SimpleNode)node.jjtGetChild(i)).getString() + ".";
                    }
                    wave += tail;
                    if(tail.equals("")){
                        wave = wave.substring(0, wave.length() - 1);
                    }
                    Wave newWave = new Wave(wave, new WaveEnvironment(w.getWaveEnv()));
                    waveQueue.incomingFront(newWave);
                }
            }
        }catch (ParseException ex) {
            throw ex;
        } catch (IOException ioEx){
            
        }
    }

    public KN getKn() {
        return kn;
    }

    public WaveInterpreter getWi() {
        return wi;
    }
    
    public SynchronousQueue<Wave> getWaveQueue() {
        return waveQueue;
    }
    
}
